#include "mapaplano.h"
#include "ciudad.h"
#include "Territorio.h"
#include <sstream>

#define RADIO (10.0f)
#define ALTURA (0.1f)
#define ANCHO_DE_REFERENCIA (1024.0f)

using namespace std;

namespace ui {
namespace tablero {
namespace mapa {

MapaPlano::MapaPlano(TexturaDeFondo &p_TexturaDeFondo, Mapa *p_Mapa) :
	MapaAbstracto(p_TexturaDeFondo, p_Mapa) {
}

MapaPlano::~MapaPlano() {
}

void MapaPlano::dibujarPlaneta() {

	GLUquadricObj *QuadObj = gluNewQuadric();
	double w = static_cast<double>(this->m_TexturaDeFondo.getAncho());
	double h = static_cast<double>(this->m_TexturaDeFondo.getAltura());

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(0.0f, static_cast<double>(w),
		0.0f, static_cast<double>(h), -10.0f, 10.0f);

	glEnable(GL_NORMALIZE);
	glEnable(GL_DEPTH_TEST);

	gluQuadricOrientation(QuadObj, GLU_OUTSIDE); 
	gluQuadricDrawStyle(QuadObj, GLU_FILL); 
	gluQuadricNormals(QuadObj, GLU_SMOOTH); 
	gluQuadricTexture(QuadObj, GL_TRUE); 

	glEnable(GL_TEXTURE_2D);
	glMatrixMode(GL_MODELVIEW);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glColor3f(255.0f, 255.0f, 255.0f);
	glNormal3f(0,0,1);

	glBegin(GL_QUADS);
		glTexCoord2i(1, 0);
		glVertex3f(w, h, 0.0f);
		glTexCoord2i(1, 1);
		glVertex3f(w, 0.0f, 0.0f);
		glTexCoord2i(0, 1);
		glVertex3f(0.0f, 0.0f, 0.0f);
		glTexCoord2i(0, 0);
		glVertex3f(0.0f, h, 0.0f );
	glEnd();	

	glDisable(GL_TEXTURE_2D); 
}

void MapaPlano::dibujarCiudades() {

	GLUquadric *t_pCiudadQuad = gluNewQuadric();

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(0.0f, static_cast<float>(this->m_iAncho),
		static_cast<float>(this->m_iAltura), 0.0f, -10.0f, 10.0f);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	glEnable(GL_NORMALIZE);
	glEnable(GL_DEPTH_TEST);
	glNormal3f(0,0,1);

	map<string, Continente*> *continentes = this->m_Mapa->obtenerContinentes();
	map<string, Continente*>::iterator itContinentes;
	
	for ( itContinentes = continentes->begin() ; itContinentes != continentes->end(); itContinentes++ ){

		Continente *c = (*itContinentes).second;
		map<string, Territorio*> *territorios = c->getTerritorios();
		map<string, Territorio*>::iterator itTerritorios;

		for ( itTerritorios = territorios->begin() ; itTerritorios != territorios->end(); itTerritorios++ ){
			Territorio *t = (*itTerritorios).second;

			glPushMatrix();
	
			Ciudad t_Ciudad(*t, this->m_TexturaDeFondo);
			glTranslatef(t_Ciudad.getU2D() * this->m_iAncho,
				t_Ciudad.getV2D() * this->m_iAltura, 0.0f);
					gluQuadricDrawStyle(t_pCiudadQuad, GLU_FILL);
			this->seleccionarColorDelTerritorio(*t);
			gluCylinder(t_pCiudadQuad, RADIO * (static_cast<float>(this->m_iAncho) / ANCHO_DE_REFERENCIA), 0.0f, ALTURA, 20, 20);

			ostringstream t_ossCantEjercitos;
			if(t->getCantidadDeEjercitos() != 0){
				t_ossCantEjercitos << t->getCantidadDeEjercitos();
				escribir(1.0f, 0.0f, 0.0f, t_ossCantEjercitos.str());
			}
			glPopMatrix();
		}
	}

	gluDeleteQuadric(t_pCiudadQuad);
}

void MapaPlano::actualizarPerspectiva(int p_iAncho, int p_iAltura) {

	this->m_iAncho = p_iAncho;
	this->m_iAltura = p_iAltura;

	this->dibujar();
}

void MapaPlano::actualizarCamara() {
	this->dibujar();
}

//Esta función está basada en cual tiene el mismo nombre del libro
//Graphics Gems volumen II y adaptada por Daniel A. Diaczun.
int	MapaPlano::intsph(Point3 raybase, Vector3 raycos, Point3 center, double radius) {

	double	dx, dy, dz;
	double	bsq, u, disc;
	double	root;

	dx   = raybase.x - center.x;
	dy   = raybase.y - center.y;
	dz   = raybase.z - center.z;
	bsq  = dx*raycos.x + dy*raycos.y + dz*raycos.z; 
	u    = dx*dx + dy*dy + dz*dz - radius*radius;
	disc = bsq*bsq - u;

	return (disc >= 0.0);
}

void MapaPlano::actualizarSeleccion(int p_x, int p_y) {

	double mm[16], pm[16];
	int v[4];
	Point3 np;

	this->m_fMouseX = p_x;
	this->m_fMouseY =  this->m_iAltura - p_y;

	glGetDoublev(GL_MODELVIEW_MATRIX, mm);
	glGetDoublev(GL_PROJECTION_MATRIX, pm);
	glGetIntegerv(GL_VIEWPORT, v);

	gluUnProject(this->m_fMouseX, this->m_fMouseY, 0.0, mm, pm, v, &np.x, &np.y, &np.z);

	this->setTerritorioSeleccionado(NULL);
	
	map<string, Continente*> *continentes = this->m_Mapa->obtenerContinentes();
	map<string, Continente*>::iterator itContinentes;
	
	for ( itContinentes = continentes->begin() ; itContinentes != continentes->end(); itContinentes++ ){

		Continente *c = (*itContinentes).second;
		map<string, Territorio*> *territorios = c->getTerritorios();
		map<string, Territorio*>::iterator itTerritorios;

		for ( itTerritorios = territorios->begin() ; itTerritorios != territorios->end(); itTerritorios++ ){
			Territorio *t = (*itTerritorios).second;

			Ciudad t_Ciudad(*t, this->m_TexturaDeFondo);
			Point3 raybase = {np.x, np.y, np.z};
			Vector3 raycos = {0.0f, 0.0f, 1.0f};
			Point3 center = {t_Ciudad.getU2D() * this->m_iAncho,
				t_Ciudad.getV2D() * this->m_iAltura, 0.0f};
			double radius = RADIO * (static_cast<float>(this->m_iAncho) / ANCHO_DE_REFERENCIA);
	
			if (intsph(raybase, raycos, center, radius)) {
				this->setTerritorioSeleccionado(&(*t));
				this->dibujar();
				break;
			}
		}
	}
}

void MapaPlano::moverCamara(mover_camara_e p_eMoverCamara) {
}

}
}
}
